package main

import (
	"fmt"
	"strconv"
)

const STACK_SIZE int = 999

var priority = map[string]int{
	"+": 4, "-": 4,
	"*": 5, "/": 5,
}

type stack struct {
	size, cur int
	top       *node
}

type node struct {
	data string
	next *node
}

func newStack(size int) (s *stack) {
	s = new(stack)
	s.size = size
	s.cur = 0
	return
}

func (s *stack) push(data string) {
	if s.cur < s.size {
		s.top = &node{data, s.top}
		s.cur++
	} else {
		fmt.Printf("full stack,%v\n", data)
	}
}

func (s *stack) pop() (data string) {
	if s.cur >= 1 {
		data = s.top.data
		s.top = s.top.next
		s.cur--
	} else {
		fmt.Printf("no data \n")
	}
	return
}

func (s *stack) get() (data string) {
	if s.top == nil {
		return ""
	}
	return s.top.data
}

func (s *stack) empty() {
	for {
		if s.top.next == nil {
			s.top = nil
			break
		}
		s.top = s.top.next
	}
	s.cur = 0
}

func (s *stack) String() (str string) {
	head := s.top
	for i := 1; i <= s.cur; i++ {
		str += string(s.top.data + "->")
		s.top = s.top.next
	}
	str = str + " size:" + strconv.Itoa(s.cur)
	s.top = head
	return str
}

func parseNiBoLan(exp string) (res []string) {
	s := newStack(STACK_SIZE)
	res = make([]string, 999)
	i := 0
	op := false
	for j := 0; j < len(exp); j++ {
		c := string(exp[j])
		if _, err := strconv.Atoi(c); err == nil {
			if op {
				c = res[i] + c
			}
			op = true
			fmt.Printf("操作数:%v\n", c)

			res[i] = c
			if j+1 == len(exp) {
				i++
			}
			continue
		}
		if op {
			i++
		}
		op = false
		fmt.Printf("操作符:%v\n", c)
		if c == "(" {
			s.push(c)
		} else if c == ")" {
			for {
				top := s.pop()
				if top == "(" {
					break
				}

				res[i] = top
				i++
			}
		} else {
			for top := s.get(); ; top = s.get() {
				if top == "" {
					s.push(c)
					break
				}
				if priority[c] < priority[top] {
					res[i] = top
					i++
					s.pop()
				} else {
					s.push(c)
					break
				}
			}
		}
	}

	for {
		if s.top != nil {
			res[i] = s.pop()
			i++
		} else {
			break
		}
	}
	return
}

/**
打印数组
*/
func printSlice(s []string) {
	for i := 0; i < len(s); i++ {
		fmt.Printf("%v ", s[i])
	}
	fmt.Printf("\n")
}

func calc(s []string) (res float64) {
	st := newStack(STACK_SIZE)
	for _, v := range s {
		if _, ok := priority[string(v)]; ok {
			res = oper(string(v), st.pop(), st.pop())
			st.push(strconv.FormatFloat(res, 'f', 3, 64))
		} else {
			st.push(string(v))
		}
	}
	return
}

func oper(op, op1, op2 string) (res float64) {
	v1, _ := strconv.ParseFloat(op2, 64)
	v2, _ := strconv.ParseFloat(op1, 64)
	switch op {
	case "+":
		res = v1 + v2
	case "-":
		res = v1 - v2
	case "*":
		res = v1 * v2
	case "/":
		res = v1 / v2
	}
	return
}

func main() {
	res := parseNiBoLan("1+(2-3)*4+10/5")

	printSlice(res)

	fmt.Printf("运算结果:%v\n", calc(res))

}
